package drds.plus.executor.command_handler.put;

import drds.plus.executor.ExecuteContext;
import drds.plus.executor.ExecutorException;
import drds.plus.executor.function.scalar.ScalarFunction;
import drds.plus.executor.record_codec.RecordCodecFactory;
import drds.plus.executor.record_codec.record.Record;
import drds.plus.executor.table.ITable;
import drds.plus.executor.utils.Utils;
import drds.plus.sql_process.abstract_syntax_tree.configuration.ColumnMetaData;
import drds.plus.sql_process.abstract_syntax_tree.configuration.IndexMapping;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.dml.IPut;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.dml.PutType;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.Item;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.function.Function;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.function.FunctionType;

import java.util.List;

public class InsertHandler extends PutHandler {

    public InsertHandler() {
        super();
    }

    protected int executePut(ExecuteContext executeContext, IPut put, ITable table, IndexMapping indexMapping) throws RuntimeException {
        int affectRows = 0;
        IPut iPut = put;

        List<Item> itemList = iPut.getUpdateItemList();

        for (int j = 0; j < iPut.getValueListListSize(); j++) {
            Record keyRecord = RecordCodecFactory.newRecordCodec(indexMapping.getKeyColumnMetaDataList()).newRecord();
            Record valueRecord = RecordCodecFactory.newRecordCodec(indexMapping.getValueColumnMetaDataList()).newRecord();
            List<Object> valueList = iPut.getValueList(j);
            L:
            for (int i = 0; i < itemList.size(); i++) {
                for (ColumnMetaData columnMetaData : indexMapping.getKeyColumnMetaDataList()) {
                    if (columnMetaData.getColumnName().equals(Utils.getColumn(itemList.get(i)).getColumnName())) {
                        Object object = valueList.get(i);
                        if (object != null) {
                            if (object instanceof Function) {
                                if (((Function) object).getFunctionType().equals(FunctionType.aggregate_function)) {
                                    throw new ExecutorException("insert is not support aggregate_function function");
                                }
                                Function function = ((Function) object);
                                object = ((ScalarFunction) function.getExtraFunction()).scalarCalucate(executeContext, null);
                            }
                        }
                        keyRecord.put(columnMetaData.getColumnName(), object);
                        continue L;
                    }
                }
                for (ColumnMetaData columnMetaData : indexMapping.getValueColumnMetaDataList()) {
                    if (columnMetaData.getColumnName().equals(Utils.getColumn(itemList.get(i)).getColumnName())) {
                        Object object = valueList.get(i);
                        if (object != null) {
                            if (object instanceof Function) {
                                if (((Function) object).getFunctionType().equals(FunctionType.aggregate_function)) {
                                    throw new ExecutorException("insert is not support aggregate_function function");
                                }
                                Function function = ((Function) object);
                                object = ((ScalarFunction) function.getExtraFunction()).scalarCalucate(executeContext, null);
                            }
                        }
                        valueRecord.put(columnMetaData.getColumnName(), object);
                        break;
                    }
                }
            }

            if (put.getPutType() == PutType.insert) {
                Record value1 = table.get(executeContext, put.getTableName(), indexMapping, keyRecord);
                if (value1 != null) {
                    throw new ExecutorException("Duplicate_entry :" + keyRecord);
                }
            }
            table.put(executeContext, put.getTableName(), indexMapping, keyRecord, valueRecord);
            affectRows++;
        }
        return affectRows;

    }
}
